use anyhow::Result;
use colored::*;
use futures::{SinkExt, StreamExt};
use notify::{RecursiveMode, Watcher};
use std::path::Path;
use tokio::sync::broadcast;
use uuid::Uuid;
use warp::{Filter, Reply};

pub async fn run(dir: String, port: u16, hot_reload: bool) -> Result<()> {
    println!("{}", "🚀 Starting static file server...".green().bold());
    println!("Directory: {}", dir.cyan());
    println!("Port: {}", port.to_string().cyan());

    if hot_reload {
        println!("{}", "🔥 Hot reload enabled".yellow().bold());
    }

    // 检查目录是否存在
    let serve_dir = Path::new(&dir);
    if !serve_dir.exists() {
        println!("{}", format!("❌ Directory '{}' does not exist", dir).red());
        return Ok(());
    }

    if !serve_dir.is_dir() {
        println!("{}", format!("❌ '{}' is not a directory", dir).red());
        return Ok(());
    }

    if hot_reload {
        run_with_hot_reload(dir, port).await
    } else {
        run_basic_server(dir, port).await
    }
}

// 基础静态服务器（无热重载）
async fn run_basic_server(dir: String, port: u16) -> Result<()> {
    let routes = warp::fs::dir(dir.clone())
        .or(warp::path::end().and(warp::fs::file(format!("{}/index.html", dir))))
        .with(warp::cors().allow_any_origin())
        .with(warp::log("serve"));

    println!("{}", "✅ Server is running!".green().bold());
    println!(
        "{}",
        format!("🌐 Local:    http://localhost:{}", port).cyan()
    );
    println!("{}", format!("🌐 Network:  http://0.0.0.0:{}", port).cyan());
    println!("{}", "Press Ctrl+C to stop the server".dimmed());

    warp::serve(routes).run(([0, 0, 0, 0], port)).await;

    Ok(())
}

// 带热重载功能的服务器
async fn run_with_hot_reload(dir: String, port: u16) -> Result<()> {
    let (reload_tx, _) = broadcast::channel::<String>(32);

    // 启动文件监听器
    let watch_dir = dir.clone();
    let reload_sender = reload_tx.clone();
    tokio::spawn(async move {
        if let Err(e) = start_file_watcher(watch_dir, reload_sender).await {
            eprintln!("File watcher error: {}", e);
        }
    });

    // WebSocket路由
    let ws_route = warp::path("__hot_reload__")
        .and(warp::ws())
        .map(move |ws: warp::ws::Ws| {
            let reload_rx = reload_tx.subscribe();
            ws.on_upgrade(move |websocket| handle_websocket(websocket, reload_rx))
        });

    // 静态文件路由（注入热重载脚本）
    let static_dir = dir.clone();
    let static_routes =
        warp::path::tail()
            .and(warp::get())
            .and_then(move |path: warp::path::Tail| {
                let dir = static_dir.clone();
                let path_str = path.as_str().to_string();
                serve_with_injection(dir, path_str)
            });

    // 根路径路由
    let index_dir = dir.clone();
    let index_route = warp::path::end().and(warp::get()).and_then(move || {
        let dir = index_dir.clone();
        serve_index_with_injection(dir)
    });

    let routes = ws_route
        .or(index_route)
        .or(static_routes)
        .with(warp::cors().allow_any_origin())
        .with(warp::log("serve"));

    println!("{}", "✅ Server with hot reload is running!".green().bold());
    println!(
        "{}",
        format!("🌐 Local:    http://localhost:{}", port).cyan()
    );
    println!("{}", format!("🌐 Network:  http://0.0.0.0:{}", port).cyan());
    println!(
        "{}",
        "🔥 Hot reload ready - changes will refresh browser automatically".yellow()
    );
    println!("{}", "Press Ctrl+C to stop the server".dimmed());

    warp::serve(routes).run(([0, 0, 0, 0], port)).await;

    Ok(())
}

// 处理WebSocket连接
async fn handle_websocket(
    websocket: warp::ws::WebSocket,
    mut reload_rx: broadcast::Receiver<String>,
) {
    let (mut ws_tx, mut ws_rx) = websocket.split();
    let client_id = Uuid::new_v4().to_string();

    println!("{}", format!("🔗 Client connected: {}", client_id).green());

    // 发送连接成功消息
    if ws_tx
        .send(warp::ws::Message::text("connected"))
        .await
        .is_err()
    {
        return;
    }

    // 监听重载信号
    let reload_task = tokio::spawn(async move {
        while let Ok(msg) = reload_rx.recv().await {
            if ws_tx.send(warp::ws::Message::text(msg)).await.is_err() {
                break;
            }
        }
    });

    // 监听WebSocket消息
    while let Some(result) = ws_rx.next().await {
        match result {
            Ok(msg) => {
                if msg.is_close() {
                    break;
                }
            }
            Err(_) => break,
        }
    }

    reload_task.abort();
    println!(
        "{}",
        format!("🔌 Client disconnected: {}", client_id).dimmed()
    );
}

// 启动文件监听器
async fn start_file_watcher(
    watch_dir: String,
    reload_sender: broadcast::Sender<String>,
) -> Result<()> {
    use notify::EventKind;

    let (tx, mut rx) = tokio::sync::mpsc::channel(100);

    let mut watcher = notify::recommended_watcher(move |res: notify::Result<notify::Event>| {
        if let Ok(event) = res {
            let _ = tx.blocking_send(event);
        }
    })?;

    watcher.watch(Path::new(&watch_dir), RecursiveMode::Recursive)?;
    println!(
        "{}",
        format!("👀 Watching for changes in: {}", watch_dir).dimmed()
    );

    while let Some(event) = rx.recv().await {
        match event.kind {
            EventKind::Modify(_) | EventKind::Create(_) | EventKind::Remove(_) => {
                // 只处理特定文件类型
                let should_reload = event.paths.iter().any(|path| {
                    if let Some(ext) = path.extension() {
                        matches!(
                            ext.to_str(),
                            Some("html") | Some("css") | Some("js") | Some("json")
                        )
                    } else {
                        false
                    }
                });

                if should_reload {
                    let file_name = event
                        .paths
                        .first()
                        .and_then(|p| p.file_name())
                        .and_then(|n| n.to_str())
                        .unwrap_or("unknown");

                    println!("{}", format!("🔄 File changed: {}", file_name).yellow());
                    let _ = reload_sender.send("reload".to_string());

                    // 添加小延迟避免重复触发
                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
                }
            }
            _ => {}
        }
    }

    Ok(())
}

// 为HTML文件注入热重载脚本
fn inject_hot_reload_script(html_content: &str) -> String {
    let hot_reload_script = r#"
<script>
(function() {
    const ws = new WebSocket('ws://localhost:' + location.port + '/__hot_reload__');
    
    ws.onopen = function() {
        console.log('%c🔥 Hot reload connected', 'color: #10b981; font-weight: bold');
    };
    
    ws.onmessage = function(event) {
        if (event.data === 'reload') {
            console.log('%c🔄 Hot reload: refreshing page...', 'color: #f59e0b; font-weight: bold');
            location.reload();
        }
    };
    
    ws.onerror = function() {
        console.log('%c❌ Hot reload connection failed', 'color: #ef4444');
    };
    
    ws.onclose = function() {
        console.log('%c🔌 Hot reload disconnected', 'color: #6b7280');
        // 尝试重连
        setTimeout(function() {
            location.reload();
        }, 1000);
    };
})();
</script>
"#;

    if html_content.contains("</body>") {
        html_content.replace("</body>", &format!("{}</body>", hot_reload_script))
    } else if html_content.contains("</html>") {
        html_content.replace("</html>", &format!("{}</html>", hot_reload_script))
    } else {
        format!("{}{}", html_content, hot_reload_script)
    }
}

// 服务带注入的静态文件
async fn serve_with_injection(
    dir: String,
    path: String,
) -> Result<warp::reply::Response, warp::Rejection> {
    let file_path = if path.is_empty() {
        format!("{}/index.html", dir)
    } else {
        format!("{}/{}", dir, path)
    };

    match tokio::fs::read_to_string(&file_path).await {
        Ok(content) => {
            if file_path.ends_with(".html") {
                let injected_content = inject_hot_reload_script(&content);
                Ok(warp::reply::html(injected_content).into_response())
            } else {
                // 非HTML文件直接返回
                let mime_type = get_mime_type(&file_path);
                Ok(warp::reply::with_header(content, "content-type", mime_type).into_response())
            }
        }
        Err(_) => {
            // 尝试作为目录处理或返回404
            let dir_path = std::path::Path::new(&file_path);
            if dir_path.is_dir() {
                let index_path = format!("{}/index.html", file_path);
                match tokio::fs::read_to_string(&index_path).await {
                    Ok(content) => {
                        let injected_content = inject_hot_reload_script(&content);
                        Ok(warp::reply::html(injected_content).into_response())
                    }
                    Err(_) => Err(warp::reject::not_found()),
                }
            } else {
                Err(warp::reject::not_found())
            }
        }
    }
}

// 服务根路径的index.html（带注入）
async fn serve_index_with_injection(dir: String) -> Result<warp::reply::Response, warp::Rejection> {
    let index_path = format!("{}/index.html", dir);

    match tokio::fs::read_to_string(&index_path).await {
        Ok(content) => {
            let injected_content = inject_hot_reload_script(&content);
            Ok(warp::reply::html(injected_content).into_response())
        }
        Err(_) => Err(warp::reject::not_found()),
    }
}

// 获取MIME类型
fn get_mime_type(file_path: &str) -> &'static str {
    if file_path.ends_with(".html") {
        "text/html"
    } else if file_path.ends_with(".css") {
        "text/css"
    } else if file_path.ends_with(".js") {
        "application/javascript"
    } else if file_path.ends_with(".json") {
        "application/json"
    } else if file_path.ends_with(".png") {
        "image/png"
    } else if file_path.ends_with(".jpg") || file_path.ends_with(".jpeg") {
        "image/jpeg"
    } else if file_path.ends_with(".gif") {
        "image/gif"
    } else if file_path.ends_with(".svg") {
        "image/svg+xml"
    } else {
        "text/plain"
    }
}
